cmake_minimum_required(VERSION 3.13)
project(msp)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED OFF)
set(CMAKE_C_EXTENSIONS OFF)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(EXISTS ${CMAKE_SOURCE_DIR}/VERSION)
    file(STRINGS ${CMAKE_SOURCE_DIR}/VERSION VERSION_LINES)
    foreach(LINE IN LISTS VERSION_LINES)
        if(LINE MATCHES "^MAJOR=(.+)$")
            set(MSP_VERSION_MAJOR ${CMAKE_MATCH_1})
        elseif(LINE MATCHES "^MINOR=(.+)$")
            set(MSP_VERSION_MINOR ${CMAKE_MATCH_1})
        elseif(LINE MATCHES "^PATCH=(.+)$")
            set(MSP_VERSION_PATCH ${CMAKE_MATCH_1})
        elseif(LINE MATCHES "^SUFFIX=(.+)$")
            set(MSP_VERSION_SUFFIX ${CMAKE_MATCH_1})
        endif()
    endforeach()
else()
    set(MSP_VERSION_MAJOR 1)
    set(MSP_VERSION_MINOR 0)
    set(MSP_VERSION_PATCH 0)
    set(MSP_VERSION_SUFFIX "")
endif()
set(MSP_VERSION "${MSP_VERSION_MAJOR}.${MSP_VERSION_MINOR}.${MSP_VERSION_PATCH}")
message(STATUS "using msp version: ${MSP_VERSION}${MSP_VERSION_SUFFIX}")

if(WIN32 AND MSVC)
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
    set(RAPTOR_BASELIB_LIBRARIES wsock32 ws2_32)
else()
    set(RAPTOR_BASELIB_LIBRARIES m pthread)
endif()

# Build option
option(MSP_BUILD_TESTS "Build Msp's unit tests" ON)
option(MSP_BUILD_BENCHMARKS "Build Msp's benchmarks" OFF)
option(MSP_BUILD_WITH_VERSION "Build Msp with version" ON)
option(MSP_INSTALL "Install Msp's header and library" ON)
option(MSP_BUILD_SHARED "Build Msp shared library" ON)

if(WIN32)
    add_definitions(-DWIN32_LEAN_AND_MEAN)
    add_definitions(-DUNICODE -D_UNICODE)
    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
    add_definitions(-DNOMINMAX)
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    add_definitions(-DDEBUG)
else()
    add_definitions(-DNDEBUG)
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} /MTd")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /MT")
    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} /MT")
    set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} /MT")

    # Disable RTTI.
    string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
else()
    # Enable strict prototype warnings for C code in clang and gcc.
    if(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
    endif(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")

    # Disable RTTI.
    string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif()

if(MSVC)
    set(WARNINGS_OPTIONS /W4 /WX)
else()
    set(WARNINGS_OPTIONS -Wall -Wextra -Werror)
endif()

if(MSP_BUILD_SHARED)
    set(MSP_LIB_TYPE SHARED)
else()
    set(MSP_LIB_TYPE STATIC)
endif()

# libmsp.so/msp.dll
file(GLOB_RECURSE MSP_SOURCES "src/*.cc")
add_library(msp ${MSP_LIB_TYPE} ${MSP_SOURCES})
target_include_directories(msp
PUBLIC
    ${PROJECT_SOURCE_DIR}
    ${PROJECT_SOURCE_DIR}/include
)
target_compile_options(msp PRIVATE ${WARNINGS_OPTIONS})

if(NOT WIN32 AND MSP_BUILD_WITH_VERSION)
    set_target_properties(msp PROPERTIES
        VERSION ${MSP_VERSION}${MSP_VERSION_SUFFIX}
        SOVERSION ${MSP_VERSION}
    )
endif()

# libprotoc.a
file(GLOB_RECURSE PROTOC_SOURCES "protoc/*.cc")
list(REMOVE_ITEM PROTOC_SOURCES "${PROJECT_SOURCE_DIR}/protoc/main.cc")
add_library(protoc STATIC ${PROTOC_SOURCES})
target_include_directories(protoc
PUBLIC
    ${PROJECT_SOURCE_DIR}/protoc
)
target_compile_options(protoc PRIVATE ${WARNINGS_OPTIONS})

# mspgen
add_executable(mspgen "${PROJECT_SOURCE_DIR}/protoc/main.cc")
target_link_libraries(mspgen PRIVATE protoc)
target_compile_options(mspgen PRIVATE ${WARNINGS_OPTIONS})

aux_source_directory(${PROJECT_SOURCE_DIR}/test/framework UT_FRAMEWORK_SRCS)
# unittest
if(MSP_BUILD_TESTS)
    enable_testing()

    function(msp_test_func test_file)
    get_filename_component(test_target_name "${test_file}" NAME_WE)
    add_executable("${test_target_name}" "")
    target_sources("${test_target_name}" PRIVATE ${UT_FRAMEWORK_SRCS} "${test_file}")
    target_link_libraries("${test_target_name}" PRIVATE msp protoc)
    target_include_directories("${test_target_name}" PRIVATE ${PROJECT_SOURCE_DIR}/test)
    target_compile_options("${test_target_name}" PRIVATE ${WARNINGS_OPTIONS})
    add_test(NAME "${test_target_name}" COMMAND "${test_target_name}")
    endfunction(msp_test_func)

    # add unittest source file
    msp_test_func("${PROJECT_SOURCE_DIR}/test/test_protoc_lexer.cc")
    msp_test_func("${PROJECT_SOURCE_DIR}/test/test_protoc_parser.cc")

endif(MSP_BUILD_TESTS)
